home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / libraris / sregexp9 / part01 / spath.c < prev    next >
C/C++ Source or Header  |  1991-05-18  |  13KB  |  554 lines

  1.  
  2. /**********************************************************************
  3.  * This is the stuff for matching to a wildcarded path. see the docs  *
  4.  *                                      *
  5.  *                                      *
  6.  *  Copyright (c) 1991 by Jon Spencer.                                *
  7.  *                                      *
  8.  *  Revision history:                              *
  9.  *    May 10, 1991        First version basically completed          *
  10.  *                                      *
  11.  **********************************************************************/
  12.  
  13. #include "sregexp.h"
  14.  
  15. extern struct DosLibrary *DOSBase;
  16.  
  17. #ifdef __DEBUG__
  18. void puts(char *);
  19. void printf(char *, ...);
  20. #endif
  21.  
  22. #define ROOT    ((struct RootNode *)DOSBase->dl_Root)
  23. #define INFO    ((struct DosInfo *)ROOT->rn_Info<<2)
  24. #define DEVC(a) ((struct DeviceList *)a<<2)
  25.  
  26. struct SpathInfo *
  27. anchorpath(anc,wld)
  28. char *anc,*wld;
  29. /* This is routine sets everything up for matching wildcard paths.
  30.    It does the expansion of any wildcards in the volume node part
  31.    of the path, if any where specified, and gets ready to roll. */
  32. {
  33.     struct SpathInfo *spi;
  34.     struct SpathNode *spn;
  35.     BPTR lock;
  36.     register char *q;
  37.     char *node,*p,c;
  38.     struct DeviceList *dvc;
  39.     struct SregExp *pat;
  40.  
  41.  
  42.     if (!(spi = getmem(sizeof(struct SpathInfo)))) {
  43.     report(MEM_ERROR);
  44.     return NULL;
  45.     }
  46.     NewList((struct List *)spi);
  47.  
  48.     for (q = wld; *q != ':' && *q != '/' && *q; q++) ;
  49.  
  50.     if (*q == ':') {
  51.     if (!(node = getmem(q - wld + 1))) {
  52.         report(MEM_ERROR);
  53.         FreeMem(spi,sizeof(struct SpathInfo));
  54.         FreeMem(spi,sizeof(struct SpathInfo));
  55.         return NULL;
  56.     }
  57.     for (q = wld, p = node; *q != ':'; )
  58.         *p++ = *q++;
  59.     *p = 0;
  60.  
  61.     pat = parsesregexp(node);
  62.     FreeMem(node,strlen(node)+1);
  63.     if (!pat) {
  64.         FreeMem(spi,sizeof(struct SpathInfo));
  65.         return NULL;
  66.     }
  67.  
  68.     /* Check if there is no path to parse */
  69.     if (*(q+1)) {
  70.         if (!(spi->spi_SregList = parsepath(q+1))) {
  71.         freesregexp(pat);
  72.         FreeMem(spi,sizeof(struct SpathInfo));
  73.         return NULL;
  74.         }
  75.     } else
  76.         spi->spi_SregList = NULL;
  77.  
  78.  
  79.     if (pat->sre_Type == SRP_NULL) {  /* check for paths matching ":..." */
  80.  
  81.         if (!(lock = Lock(anc,SHARED_LOCK))) {
  82.         freesregexp(pat);
  83.         freespathinfo(spi);
  84.         return NULL;
  85.         }
  86.         if (!(node = getmem(2))) {
  87.         report(MEM_ERROR);
  88.         UnLock(lock);
  89.         freesregexp(pat);
  90.         freespathinfo(spi);
  91.         return NULL;
  92.         }
  93.         node[0] = ':';
  94.         node[1] = 0;
  95.         if (!(spn = makespathnode(lock,node,spi->spi_SregList))) {
  96.         UnLock(lock);
  97.         FreeMem(node,2);
  98.         freesregexp(pat);
  99.         freespathinfo(spi);
  100.         return NULL;
  101.         }
  102.         spn->spn_NodeName = node;
  103.         AddTail((struct List *)spi,(struct Node *)spn);
  104.         UnLock(lock);
  105.     } else {
  106.         for (dvc = DEVC(INFO->di_DevInfo); dvc; dvc = DEVC(dvc->dl_Next)) {
  107.         p = (char *)dvc->dl_Name<<2;
  108.         if (matchnsregexp(p+1,pat,FALSE,*p)) {
  109.             if (!(node = getmem(*p+2))) {
  110.             report(MEM_ERROR);
  111.             freesregexp(pat);
  112.             freespathinfo(spi);
  113.             return NULL;
  114.             }
  115.             for (c = *p++, q = node; c > 0; c--)
  116.             *q++ = *p++;
  117.             *q++ = ':';
  118.             *q = 0;
  119.             if (dvc->dl_Type == DLT_DEVICE) {
  120.             lock = Lock(node,SHARED_LOCK);  /* ignore non-filesystem devices */
  121.             if (!lock)
  122.                 continue;
  123.             UnLock(lock);
  124.             }
  125.             if (!(spn = makespathnode(NULL,node,spi->spi_SregList))) {
  126.             FreeMem(node,strlen(node)+1);
  127.  
  128.             freespathinfo(spi);
  129.             return NULL;
  130.             }
  131.             spn->spn_NodeName = node;
  132.             AddTail((struct List *)spi,(struct Node *)spn);
  133.         }
  134.         }
  135.     }
  136.     freesregexp(pat);
  137.     } else {
  138.     /* check if there is any path to parse */
  139.     if (*wld) {
  140.         if (!(spi->spi_SregList = parsepath(wld))) {
  141.         FreeMem(spi,sizeof(struct SpathInfo));
  142.         return NULL;
  143.         }
  144.     } else
  145.         spi->spi_SregList = NULL;
  146.  
  147.     if (!(spn = makespathnode(NULL,anc,spi->spi_SregList)))
  148.         freespathinfo(spi);
  149.     AddTail((struct List *)spi,(struct Node *)spn);
  150.     }
  151.     return spi;
  152. }
  153.  
  154. #undef ROOT
  155. #undef INFO
  156. #undef DEVC
  157.  
  158. struct SregList *
  159. parsepath(wld)
  160. char *wld;
  161. /* This routine takes a wildcarded path and turns it into a singly
  162.    linked list of SregExp structures, one node for each path element. */
  163. {
  164.     char *q,*p,*cp,c = 1,recurse;
  165.     struct SregExp *sre;
  166.     struct SregList *srl,*srr = NULL;
  167.  
  168.     if (!(cp = getmem(strlen(wld)+1))) {
  169.     report(MEM_ERROR);
  170.     return NULL;
  171.     }
  172.     strcpy(cp,wld);
  173.  
  174.     q = cp;
  175.     while (*q && c) {
  176.     if (strncmp(q,".../",4) == 0) {
  177.         recurse = SRF_RECURSE;
  178.         q += 4;
  179.     } else
  180.         recurse = 0;
  181.     p = q;
  182.     while (*q && *q != '/') q++;
  183.     c = *q;
  184.     *q = 0;
  185.     if (!(sre = parsesregexp(p)))
  186.         goto bad;
  187.     sre->sre_Flag |= recurse;
  188.     *q++ = c;
  189.     if (!srr) {
  190.         if (!(srl = srr = getmem(sizeof(struct SregList)))) {
  191.         report(MEM_ERROR);
  192.         goto bad;
  193.         }
  194.     } else {
  195.         if (!(srl = (srl->srl_next = getmem(sizeof(struct SregList))))) {
  196.         report(MEM_ERROR);
  197.         goto bad;
  198.         }
  199.     }
  200.     srl->srl_next = NULL;
  201.     srl->srl_sreg = sre;
  202.     }
  203.     if (c == '/')           /* If path ends in a / then just take dirs */
  204.     srl->srl_sreg->sre_Flag |= SRF_JUSTDIRS;
  205.  
  206.     FreeMem(cp,strlen(cp)+1);
  207.     return srr;
  208.  
  209. bad:
  210.     if (sre)
  211.     freesregexp(sre);
  212.     FreeMem(cp,strlen(cp)+1);
  213.  
  214.     while (srl) {
  215.     if (srl->srl_sreg)
  216.         freesregexp(srl->srl_sreg);
  217.     FreeMem(srl,sizeof(struct SregList));
  218.     srl = srl->srl_next;
  219.     }
  220.     return NULL;
  221. }
  222.  
  223. struct SpathNode *
  224. makespathnode(lock,file,sreg)
  225. BPTR lock;
  226. char *file;
  227. struct SregList *sreg;
  228. /* This routine makes a new node to be linked into the list of current
  229.    directory locks, basically */
  230. {
  231.     struct SpathNode *spn;
  232.     BPTR cdir;
  233.  
  234.  
  235.     if (!(spn = getmem(sizeof(struct SpathNode)))) {
  236.     report(MEM_ERROR);
  237.     return NULL;
  238.     }
  239.     if (lock)
  240.     cdir = CurrentDir(lock);
  241.     if (!(spn->spn_Lock = Lock(file,SHARED_LOCK))) {
  242.     FreeMem(spn,sizeof(struct SpathNode));
  243.     return NULL;
  244.     }
  245.     spn->spn_SregList = sreg;
  246.     if (!(Examine(spn->spn_Lock,&spn->spn_FIB))) {
  247.     UnLock(spn->spn_Lock);
  248.     FreeMem(spn,sizeof(struct SpathNode));
  249.     return NULL;
  250.     }
  251.     spn->spn_Flags = 0;
  252.     spn->spn_NodeName = NULL;
  253.     if (lock)
  254.     CurrentDir(cdir);
  255.  
  256.     return spn;
  257. }
  258.  
  259.  
  260.  
  261. #define FILENAME    (spn->spn_FIB.fib_FileName)
  262. #define NEXTPATH    (spn->spn_SregList->srl_next)
  263. #define THISPATH    (spn->spn_SregList)
  264. #define LOCK        (spn->spn_Lock)
  265. #define FIB        (spn->spn_FIB)
  266. #define SREG        (spn->spn_SregList->srl_sreg)
  267. #define ISDIR        (FIB.fib_DirEntryType > 0)
  268. #define ISRECURSE    (SREG->sre_Flag & SRF_RECURSE)
  269. #define ISDONEONCE    (spn->spn_Flags & SPF_DONEONCE)
  270. #define ISJUSTDIRS    (SREG->sre_Flag & SRF_JUSTDIRS)
  271. #define WANTIT        (ISDIR ? dirs >= 0 : !ISJUSTDIRS && dirs <= 0)
  272. #define SIGBREAKF_ANY    (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F)
  273.  
  274. int
  275. nextfile(spi,buf,len,dirs)
  276. struct SpathInfo *spi;
  277. char *buf;
  278. int len,dirs;
  279. /* This routine is a mess.  It jumps all over the place and is generally
  280.    hard to follow.  The basic idea behind it is to implement recursion,
  281.    but without using the stack.  Basically the linked list of SpathNode
  282.    structures, anchored in the SpathInfo structure works as our stack
  283.    for us.  "Why not just use the stack?" you ask.  Well, unfortunately,
  284.    we have to return in the middle of the scan, each time a new match
  285.    is found.  This would mean unrolling all of the stack that defines
  286.    how far through the search we are to get back to the return address.
  287.    By using the linked list of SpathInfo structures, we can preserve
  288.    the state of the 'stack' betweem calls. */
  289. {
  290.     struct SpathNode *spn;
  291.  
  292.  
  293. try_again:
  294.  
  295.     if (SetSignal(0,0) & SIGBREAKF_ANY)
  296.     return SPE_SIGBREAK;
  297.  
  298.     spn = spi->spi_TailPred;
  299.  
  300.     /* check if we're done. */
  301.     if (!spn->spn_Pred) {
  302.     report(ERROR_NO_MORE_ENTRIES);
  303.     return SPE_ALL_DONE;
  304.     }
  305.  
  306.     /* check if we're at the end of the path: used to match just nodes.*/
  307.     if (!THISPATH) {
  308.     if (ISDONEONCE)
  309.         goto pop;
  310.  
  311.     spn->spn_Flags |= SPF_DONEONCE;
  312.  
  313.     if (dirs >= 0) {
  314.         return buildpath(spi,buf,len);
  315.     } else
  316.         goto pop;
  317.     }
  318.  
  319.     /* check if we set a delayed decend */
  320.     if (spn->spn_Flags & SPF_DECEND)
  321.     goto decend;
  322.  
  323.     /* check if it matches the null string, ie parent dir */
  324.     if (SREG->sre_Type == SRP_NULL) {
  325.  
  326.     /* Check if its done or there is no parent. */
  327.     if (ISDONEONCE || !ParentDir(LOCK))
  328.         goto pop;
  329.  
  330.     spn->spn_Flags |= SPF_DONEONCE;       /* Mark it as done. */
  331.  
  332.     /* mark it as parent match for buildpath */
  333.     spn->spn_Flags |= SPF_NEXTPARENT;
  334.  
  335.     if (!(spn = makespathnode(LOCK,"/",NEXTPATH)))
  336.         return SPE_ERROR;
  337.     AddTail((struct List *)spi,(struct Node *)spn);
  338.     goto try_again;
  339.     }
  340.  
  341.     /* Check if we can do it quickly */
  342.     if ((SREG->sre_Type == SRP_STRING ||
  343.                   SREG->sre_Type == SRP_ONECHAR) && !ISRECURSE) {
  344.     BPTR cdir,lock;
  345.  
  346.     /* Have we already done it? */
  347.     if (ISDONEONCE)
  348.        goto pop;
  349.  
  350.     /* Mark it as done. */
  351.     spn->spn_Flags |= SPF_DONEONCE;
  352.  
  353.     cdir = CurrentDir(LOCK);
  354.     if (SREG->sre_Type == SRP_STRING)
  355.         lock = Lock(SREG->sre_Data.string,SHARED_LOCK);
  356.     else {
  357.         char n[2];
  358.  
  359.         n[0] = SREG->sre_Data.onechar;
  360.         n[1] = 0;
  361.         lock = Lock(n,SHARED_LOCK);
  362.     }
  363.     CurrentDir(cdir);
  364.     if (!lock)
  365.         goto pop;
  366.     if (!Examine(lock,&FIB)) {
  367.         UnLock(lock);
  368.         return SPE_ERROR;
  369.     }
  370.     UnLock(lock);
  371.  
  372.     if (!NEXTPATH) {
  373.         if (WANTIT)
  374.         return buildpath(spi,buf,len);
  375.         else
  376.         goto pop;
  377.     }
  378.     if (ISDIR) {
  379.         if (!(spn = makespathnode(LOCK,FILENAME,NEXTPATH))) {
  380.         return SPE_ERROR;
  381.         }
  382.         AddTail((struct List *)spi,(struct Node *)spn);
  383.         goto try_again;
  384.     }
  385.     goto pop;
  386.     }
  387.  
  388.     while (ExNext(LOCK,&FIB)) {
  389.     if (SetSignal(0,0) & SIGBREAKF_ANY)
  390.         return SPE_SIGBREAK;
  391.  
  392.     if (matchsregexp(FILENAME,SREG,FALSE)) {
  393.         if (ISDIR && ISRECURSE)
  394.         spn->spn_Flags |= SPF_DECEND;
  395.         if (!NEXTPATH) {
  396.         if (WANTIT)
  397.             return buildpath(spi,buf,len);
  398.         } else if (ISDIR) {
  399.         if (!(spn = makespathnode(LOCK,FILENAME,NEXTPATH))) {
  400.             return SPE_ERROR;
  401.         }
  402.         AddTail((struct List *)spi,(struct Node *)spn);
  403.         goto try_again;
  404.         }
  405.     }
  406.     if (ISDIR && ISRECURSE) {
  407. decend:
  408.         spn->spn_Flags &= ~SPF_DECEND;
  409.         if (!(spn = makespathnode(LOCK,FILENAME,THISPATH))) {
  410.         return SPE_ERROR;
  411.         }
  412.         AddTail((struct List *)spi,(struct Node *)spn);
  413.         goto try_again;
  414.     }
  415.     }
  416.  
  417.     if (IoErr() != ERROR_NO_MORE_ENTRIES)
  418.     return SPE_ERROR;
  419.  
  420. pop:
  421.     RemTail((struct List*)spi);
  422.     freespathnode(spn);
  423.     goto try_again;
  424. }
  425.  
  426. #undef FILENAME
  427. #undef NEXTPATH
  428. #undef THISPATH
  429. #undef LOCK
  430. #undef FIB
  431. #undef SREG
  432. #undef ISDIR
  433. #undef ISRECURSE
  434. #undef ISDONEONCE
  435. #undef ISJUSTDIRS
  436. #undef WANTIT
  437.  
  438.  
  439. int
  440. buildpath(spi,buf,len)
  441. struct SpathInfo *spi;
  442. char *buf;
  443. int len;
  444. /* This routine turns the current 'stack' of SpathNode structures into
  445.    a file name the AmigaDOS will like. */
  446. {
  447.     struct SpathNode *spn = spi->spi_Head;
  448.     int i = 0;
  449.     char *q;
  450.  
  451.     if (len < 1)
  452.     return SPE_BUFF_FULL;
  453.  
  454.     if (spn->spn_Succ && spn->spn_NodeName) {
  455.     while (spn->spn_Succ->spn_Succ && spn->spn_Succ->spn_NodeName) {
  456.         spn = spn->spn_Succ;
  457.     }
  458.     }
  459.  
  460.     if (q = spn->spn_NodeName) {
  461.     while (*q && i < len)
  462.         buf[i++] = *q++;
  463.     if (i >= len)
  464.         return SPE_BUFF_FULL;
  465.     }
  466.     while (spn->spn_Succ) {
  467.     if (spn->spn_Flags & SPF_NEXTPARENT) {
  468.         buf[i++] = '/';
  469.         if (i >= len)
  470.         return SPE_BUFF_FULL;
  471.     } else {
  472.         q = spn->spn_FIB.fib_FileName;
  473.         while (*q && i < len)
  474.         buf[i++] = *q++;
  475.         if (i >= len)
  476.         return SPE_BUFF_FULL;
  477.         if (spn->spn_Succ->spn_Succ ||
  478.               spn->spn_SregList->srl_sreg->sre_Flag & SRF_JUSTDIRS) {
  479.         buf[i++] = '/';
  480.         if (i >= len)
  481.             return SPE_BUFF_FULL;
  482.         }
  483.     }
  484.     spn = spn->spn_Succ;
  485.     }
  486.  
  487.     buf[i] = 0;
  488.     return i;
  489. }
  490.  
  491. void
  492. freespathinfo(spi)
  493. struct SpathInfo *spi;
  494. /* This routine frees all of the resoureces tied up in a SpathInfo
  495.    structure */
  496. {
  497.     struct SpathNode *spn;
  498.     struct SregList *srl,*next;
  499.  
  500.     while (spn = (struct SpathNode *)RemTail((struct List *)spi))
  501.     freespathnode(spn);
  502.  
  503.     for (srl = spi->spi_SregList; srl; srl = next) {
  504.     freesregexp(srl->srl_sreg);
  505.     next = srl->srl_next;
  506.     FreeMem(srl,sizeof(struct SregList));
  507.     }
  508.  
  509.     FreeMem(spi,sizeof(struct SpathInfo));
  510. }
  511.  
  512. void
  513. freespathnode(spn)
  514. struct SpathNode *spn;
  515. /* This routine frees the memory and lock in a SpathNode structure. */
  516. {
  517.     if (spn->spn_NodeName) {
  518.     FreeMem(spn->spn_NodeName,strlen(spn->spn_NodeName)+1);
  519.     }
  520.     UnLock(spn->spn_Lock);
  521.     FreeMem(spn,sizeof(struct SpathNode));
  522. }
  523.  
  524.  
  525. #ifdef __DEBUG__
  526.  
  527. /* This is some debugging stuff, not compiled into the release version. */
  528.  
  529. void
  530. puts(c)
  531. char *c;
  532. {
  533.     Write(Output(),c,strlen(c));
  534.     Write(Output(),"\n",1);
  535. }
  536.  
  537. #include <stdarg.h>
  538.  
  539. extern void vsprintf(char *, char *, va_list);
  540.  
  541. void printf(f, ...)
  542. char *f;
  543. {
  544.     char buff[100];
  545.     va_list va;
  546.  
  547.     va_start(va,f);
  548.     vsprintf(buff,f,va);
  549.     va_end(va);
  550.     Write(Output(),buff,strlen(buff));
  551. }
  552.  
  553. #endif
  554.